/**
 * 
 * <p>
 * Segment
 * </p>
 * 
 * @author <a href="mailto:sylvain.meignier@lium.univ-lemans.fr">Sylvain Meignier</a>
 * @author <a href="mailto:gael.salaun@univ-lemans.fr">Gael Salaun</a>
 * @author <a href="mailto:teva.merlin@lium.univ-lemans.fr">Teva Merlin</a>
 * @version v2.0
 * 
 *          Copyright (c) 2007-2009 Universite du Maine. All Rights Reserved. Use is subject to license terms.
 * 
 *          THIS SOFTWARE IS PROVIDED BY THE "UNIVERSITE DU MAINE" AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 *          TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE
 *          LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *          GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 *          STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 *          OF SUCH DAMAGE.
 * 
 *          Segment
 * 
 */

package fr.lium.spkDiarization.libClusteringData;

import java.util.ArrayList;
import java.util.TreeMap;

import fr.lium.spkDiarization.libClusteringData.transcription.EntitySet;
import fr.lium.spkDiarization.libClusteringData.transcription.LinkSet;

public class Segment implements Comparable<Segment>, Cloneable {


	// Type of recording conditions.
	public enum BandType {
		BUNK, TEL, STUDIO
	}

	public final static float Rate = 100.0f;

	public static final String keyScore = "score";
	public static final String keyWords = "words";
	public static final String keyChannel = "channel";
	public static final String keyBand = "band";
	public static final String keyEnvironment = "env";
	public static final String keyGender = "gender";
//	public static final String keyLinkSet = "linkSet";
//	public static final String keyEntities = "entities";

	public static final int nbBand = 3;
	// Array of string corresponding to a Band enum
	public static final String[] bandStrings = { "U", "T", "S" };
	// Array of string corresponding to a Band enum for F0 and F2
	public static final String[] bandFStrings = { "unk", "F2", "F0" };
	public static final int nbEnv = 4;
	// Array of string corresponding to a Environment enum
	public static final String[] environmentStrings = { "U", "P", "M", "S" };

        private String uuid;

        private String showName; // Name of the show.
	private int startIndex; // Start time in feature.
	private int length; // Length of the segment
	private Cluster cluster;

	// Link between Segmentation and features
	private ArrayList<int[]> top; // storage for top gaussian
	private ArrayList<Boolean> usedFeatures; // storage for used / unused
	// features during training,
	// scoring ..
	private boolean usedFeaturesActive;

	private TreeMap<String, Object> information;
	private Object userData;
	private EntitySet entitySet;
	private LinkSet linkSet;
	
	public Segment(String showName, int startIndex, int lenght, Cluster cluster) {
		// index = maximumIndex++;
		// this.showIndex = showIndex;
		this.showName = showName;
		this.startIndex = startIndex;
		this.length = lenght;
		this.cluster = cluster;
		top = new ArrayList<int[]>();
		usedFeatures = new ArrayList<Boolean>();
		usedFeaturesActive = false;
		information = new TreeMap<String, Object>();
		userData = null;
		linkSet = new LinkSet(0);
		entitySet = new EntitySet();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Segment) {
			Segment other = (Segment) obj;
			if ((other.showName == showName) && (other.startIndex == startIndex) && (other.length == length)) {
				return true;
			} else {
				System.err.printf("+ segment no equal showname:" + (other.showName == showName) + " start:" + (other.startIndex == startIndex) + " lenght:"
						+ (other.length == length));
			}
		}
		return false;
	}

	/**
	 * Creates a deep copy of the segment: the content of top is copied, not just referenced.
	 */
	@Override
	public Object clone() {
		Segment result = null;
		try {
			result = (Segment) (super.clone());
		} catch (CloneNotSupportedException e) {
		}
                result.uuid = uuid;
		result.top = new ArrayList<int[]>(top.size());
		for (int i = 0; i < top.size(); i++) {
			result.top.add(top.get(i).clone());
		}
		result.information = new TreeMap<String, Object>();
		for (String key : information.keySet()) {
			/*
			 * Iterator<String> it = information.keySet().iterator(); while (it.hasNext()) { String key = it.next();
			 */
			result.setInformation(key, information.get(key));
		}
		try {
			result.linkSet = (LinkSet) linkSet.clone();
			result.entitySet = (EntitySet) entitySet.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return result;
	}

	public int compareTo(Segment seg) {
		int compare = showName.compareTo(seg.showName);
		if (compare == 0) {
			if (startIndex < seg.startIndex) {
				return -1;
			} else {
				return (startIndex > seg.startIndex) ? 1 : 0;
			}
		}
		return compare;
	}

	public void debug(int level) {
		System.out.print("debug[Segment] \t seg show= " + getShowName());
		System.out.print(" channel= " + getChannel());
		System.out.print(" start= " + getStart() + " len= ");
		System.out.print(getLength() + " end="+getLast()+" clusterGender= " + cluster.getGender());
		System.out.print(" band= " + getBand() + " env= " + getEnv());
		System.out.println(" clusterName= " + getClusterName() + " " + getInformations());
		if (level > 1) {
			LinkSet linkSet = getLinkSet();
			if (linkSet != null) {
				linkSet.debug();
			}
/*			if (getEntities() != null) {
				getEntities().debug();
			}*/
		}
	}

	/**
	 * Get the band type
	 */
	public String getBand() {
		String res = (String) information.get(keyBand);
		if (res == null) {
			return bandStrings[0];
		}
		return res;
	}

	/**
	 * Get the channel type
	 */
	public String getChannel() {
		String res = (String) information.get(keyChannel);
		if (res == null) {
			return "1";
		}
		return res;
	}

	/**
	 * Get the name
	 */
	public Cluster getCluster() {
		return cluster;

	}

	/**
	 * Get the name
	 */
	public String getClusterName() {
		return cluster.getName();

	}

	/**
	 * Get the environment type
	 */
	public String getEnv() {
		String res = (String) information.get(keyEnvironment);
		if (res == null) {
			return environmentStrings[0];
		}
		return res;
	}

	/**
	 * public String getGender() { String res = (String) information.get(keyGender); if (res == null) { return Cluster.genderStrings[0]; } return res; }
	 **/

	public TreeMap<String, Object> getInformation() {
		return information;
	}

	public Object getInformation(Object key) {
		return information.get(key);
	}

	public String getInformation(String key) {
		return information.get(key).toString();
	}

	public String getInformations() {
		String res = "";
		for (String key : information.keySet()) {
			/*
			 * Iterator<String> it = information.keySet().iterator(); while (it.hasNext()) { String key = it.next().toString();
			 */
			if ((key != keyChannel) && (key != keyBand) && (key != keyEnvironment) && (key != keyGender)) {
				res = res + " [ " + key + " = " + information.get(key) + " ]";
			}
		}
		return res;

	}

	/**
	 * Get the last index of the segment
	 */
	public int getLast() {
		return startIndex + length - 1;
	}

	public float getLastInSecond() {
		return (getLast()) / Rate;
	}

	public float getEndInSecond() {
		return (getLast()+1) / Rate;
	}

	/**
	 * Get the length of the segment
	 */
	public int getLength() {
		return length;
	}

	public float getLengthInSecond() {
		return (length) / Rate;
	}

	public double getScore() {
		return (Double) information.get(keyScore);
	}

	/**
	 * Get the name of the show
	 */
	public String getShowName() {
		return showName;
	}

	/**
	 * Get the start index of the segment
	 */
	public int getStart() {
		return startIndex;
	}

	public float getStartInSecond() {
		return (startIndex) / Rate;
	}

	public ArrayList<int[]> getTop() {
		return top;
	}

	public boolean getUsedFeature(int idx) {
		return usedFeatures.get(idx);
	}

	public ArrayList<Boolean> getUsedFeatures() {
		return usedFeatures;
	}

	public Object getUserData() {
		return userData;
	}

	/**
	 * Get the word list
	 */
	public String getWordList() {
		return (String) information.get(keyWords);
	}

	public boolean isUsedFeaturesActive() {
		return usedFeaturesActive;
	}

	public void removeInformation(Object key) {
		information.remove(key);
	}

	/**
	 * Set band type coming from #strBand
	 */
	public void setBand(String c) {
		information.put(keyBand, c);
	}

	/**
	 * Set channel type
	 */
	public void setChannel(String c) {
		information.put(keyChannel, c);
	}

	/**
	 * Set the tmp name
	 */
	/**
	 * Set the tmp name
	 */
	public void setCluster(Cluster c) {
		cluster = c;
	}

	/**
	 * Set band type coming from #strEnv
	 */
	public void setEnv(String c) {
		information.put(keyEnvironment, c);
	}

	/**
	 * public void setGender(String c) { information.put(keyGender, c); }
	 **/

	public void setInformation(String key, Object value) {
		information.put(key, value);
	}

	/**
	 * Set the length of a segment in number of features
	 */
	public void setLength(int c) {
		length = c;
	}

	public void setScore(double c) {
		information.put(keyScore, c);
	}

	/**
	 * Set index of the show
	 * 
	 * public void setShowIndex(int c) { showIndex = c; }
	 */

	/**
	 * Set show name
	 */
	public void setShowName(String c) {
		showName = c;
	}

	/**
	 * Set start of the segment, ie a feature index
	 */
	public void setStart(int c) {
		startIndex = c;
	}

	public void setUsedFeature(int idx, boolean value) {
		for (int i = usedFeatures.size(); i <= idx; i++) {
			usedFeatures.add(true);
		}
		usedFeatures.set(idx, value);
	}

	public void setUsedFeatures(ArrayList<Boolean> usedFeatures) {
		this.usedFeatures = usedFeatures;
	}

	public void setUsedFeaturesActive(boolean usedFeaturesActive) {
		this.usedFeaturesActive = usedFeaturesActive;
	}

	public void setUserData(Object userData) {
		this.userData = userData;
	}

	/**
	 * Set the word list
	 */
	public void setWordList(String c) {
		information.put(keyWords, c);
	}

	/**
	 * Get the sausage set of the segment
	 * 
	 * @return FSMSausageSet
	 */
	public LinkSet getLinkSet() {
		return linkSet;
	}

	public void setLinkSet(LinkSet linkSet) {
		this.linkSet = linkSet;;
	}

	public EntitySet getEntities() {
		return entitySet;
	}

	public void setEntities(EntitySet entities) {
		entitySet = entities;
	}
            /**
     * @return the uuid
     */
    public String getUuid() {
        return uuid;
    }

    /**
     * @param uuid the uuid to set
     */
    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
}
